<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <style>
            #mainCanvas {
                position: absolute;
                left: 0;
                right: 0;
                top: 0;
                bottom: 0;
            }

            #info {
                position: absolute;
                z-index: 10;
                left: 10px;
                bottom: 10px;
            }
        </style>
    </head>

    <body onload="init()">
        <canvas id="mainCanvas" width="800px" height="600px" ></canvas>

        <div id="info">
            <a href="http://zhangwenli.com" target="_blank" onclick="_gaq.push(['_trackEvent', 'ToHome', 'InProject', 'Cezanne']);">Author</a>
            <a href="https://github.com/Ovilia/cezanne" target="_blank" onclick="_gaq.push(['_trackEvent', 'ToGitHub', 'InProject', 'Cezanne']);">View at GitHub</a>
        </div>

        <script src="lib/three.js"></script>
        <script src="lib/OBJLoader.js"></script>
        <script src="lib/MTLLoader.js"></script>
        <script src="lib/OrbitControls.js"></script>
        <script src="lib/zepto.js"></script>
        <script src="lib/stats.min.js"></script>
        <script src="lib/dat.gui.min.js"></script>

        <script>
            var scene = null;
            var camera = null;
            var renderer = null;

            var appleMesh = null;
            var stemMesh = null;
            var groupMesh = null;
            var appleMat = null;
            var stemMat = null;

            var keyLight = null;
            var fillLight = null;
            var backLight = null;

            var controls = null;

            var shaders = [];
            var shaderConfig = null;

            var gui = null;

            var stats = new Stats();
            document.body.appendChild(stats.dom);

            function init() {
                var canvas = document.getElementById('mainCanvas');
                canvas.width = window.innerWidth;
                canvas.height = window.innerHeight;

                renderer = new THREE.WebGLRenderer({
                    canvas: canvas,
                    antialias: true
                });
                renderer.setClearColor(0xf3f3f3);
                scene = new THREE.Scene();

                camera = new THREE.PerspectiveCamera(60, canvas.width / canvas.height, 10, 10000);
                camera.position.set(133, 37, -36);
                scene.add(camera);

                controls = new THREE.OrbitControls(camera, renderer.domElement);
                controls.addEventListener('change', draw);

                var mtlLoader = new THREE.MTLLoader();
                mtlLoader.setPath('./model/');
                mtlLoader.load('apple.mtl', function(materials) {
                    materials.preload();

                    // model loader
                    var objLoader = new THREE.OBJLoader();
                    objLoader.setMaterials(materials);
                    objLoader.setPath('./model/');
                    objLoader.load('apple.obj', function (obj) {
                        obj.traverse(function(child) {
                            if (child instanceof THREE.Mesh) {
                                if (!appleMesh) {
                                    appleMesh = child;
                                    appleMat = appleMesh.material;
                                }
                                else {
                                    stemMesh = child;
                                    stemMat = stemMesh.material;
                                }
                            }
                        });

                        groupMesh = obj;
                        groupMesh.position.set(-50, -50, 0);
                        scene.add(groupMesh);
                    });
                });

                keyLight = new THREE.SpotLight(0xffffff, 1, 5000, Math.PI / 6, 25);
                keyLight.position.set(1000, 1000, 500);
                keyLight.target.position.set(100, 0, 0);
                scene.add(keyLight);

                fillLight = new THREE.SpotLight(0xffffff, 0.4, 1000, Math.PI / 6, 25);
                fillLight.position.set(80, -20, -200);
                fillLight.target.position.set(0, 0, -200);
                scene.add(fillLight);

                backLight = new THREE.AmbientLight(0xffffff, 0.2);
                scene.add(backLight);

                // drawAxes();

                tick();

                $.get('./shader/shader.config.json', function (data) {
                    shaderConfig = data;
                    initControl();
                });
            }

            function tick() {
                stats.begin();

                draw();

                stats.end();

                requestAnimationFrame(tick);
            }

            function draw() {
                renderer.render(scene, camera);
            }

            function useShader(name) {
                if (name === 'none') {
                    appleMesh.material = appleMat;
                    stemMesh.material = stemMat;
                    return;
                }

                if (!shaderConfig) {
                    // try after a second
                    setTimeout(function () {
                        useShader(name);
                    }, 1000);
                    return;
                }

                var lightUniform = {
                    type: 'v3',
                    value: keyLight.position
                };
                setShader('apple', appleMesh, {
                    uniforms: {
                        color: {
                            type: 'v3',
                            value: new THREE.Color('#f55c1f')
                        },
                        light: lightUniform
                    }
                });
                setShader('stem', stemMesh, {
                    uniforms: {
                        color: {
                            type: 'v3',
                            value: new THREE.Color('#60371b')
                        },
                        light: lightUniform
                    }
                });

                function setShader(meshName, mesh, qualifiers) {
                    var config = shaderConfig[name][meshName];

                    if (shaders[name]) {
                        // use pre-loaded shader
                        mesh.material = shaders[name][meshName];
                    }
                    else {
                        // load
                        $.get('./shader/' + config.path + '.vs', function (vs) {
                            $.get(
                                './shader/' + config.path + '.fs',
                                function (fs) {
                                    appleShader(vs, fs);
                                }
                            )
                        })
                    }

                    function appleShader(vs, fs) {
                        var material = new THREE.ShaderMaterial({
                            vertexShader: vs,
                            fragmentShader: fs,
                            uniforms: qualifiers.uniforms
                        });
                        mesh.material = material;

                        if (!shaders[name]) {
                            shaders[name] = {};
                        }
                        shaders[name][meshName] = material;
                    }
                }
            }

            function drawAxes() {
                // x-axis
                var xGeo = new THREE.Geometry();
                xGeo.vertices.push(new THREE.Vector3(0, 0, 0));
                xGeo.vertices.push(new THREE.Vector3(1000, 0, 0));
                var xMat = new THREE.LineBasicMaterial({
                    color: 0xff0000
                });
                var xAxis = new THREE.Line(xGeo, xMat);
                scene.add(xAxis);

                // y-axis
                var yGeo = new THREE.Geometry();
                yGeo.vertices.push(new THREE.Vector3(0, 0, 0));
                yGeo.vertices.push(new THREE.Vector3(0, 1000, 0));
                var yMat = new THREE.LineBasicMaterial({
                    color: 0x00ff00
                });
                var yAxis = new THREE.Line(yGeo, yMat);
                scene.add(yAxis);

                // z-axis
                var zGeo = new THREE.Geometry();
                zGeo.vertices.push(new THREE.Vector3(0, 0, 0));
                zGeo.vertices.push(new THREE.Vector3(0, 0, 1000));
                var zMat = new THREE.LineBasicMaterial({
                    color: 0x00ccff
                });
                var zAxis = new THREE.Line(zGeo, zMat);
                scene.add(zAxis);
            }

            window.onresize = function () {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
                draw();
            };

            function initControl() {
                gui = new dat.GUI();

                var shaderNames = ['none'];
                for (var shader in shaderConfig) {
                    shaderNames.push(shader);
                }

                var option = {
                    'Shader': 'none',
                    'Light X': keyLight.position.x,
                    'Light Y': keyLight.position.y,
                    'Light Z': keyLight.position.z
                };

                // shader
                gui.add(option, 'Shader', shaderNames)
                    .onChange(function (value) {
                        useShader(value);
                    });

                // light
                var lightFolder = gui.addFolder('Light');
                lightFolder.add(option, 'Light X')
                    .min(-2000).max(2000)
                    .onChange(function (value) {
                        keyLight.position.x = value;

                    });
                lightFolder.add(option, 'Light Y')
                    .min(-2000).max(2000)
                    .onChange(function (value) {
                        keyLight.position.y = value;
                    });
                lightFolder.add(option, 'Light Z')
                    .min(-2000).max(2000)
                    .onChange(function (value) {
                        keyLight.position.z = value;
                    });
            }
        </script>

        <script type="text/javascript">
            (function() {
              var hm = document.createElement("script");
              hm.src = "//hm.baidu.com/hm.js?dcee78e565eeaedc76defba5d096b344";
              var s = document.getElementsByTagName("script")[0];
              s.parentNode.insertBefore(hm, s);
            })();

            var _gaq = _gaq || [];
            _gaq.push(['_setAccount', 'UA-38205696-1']);
            _gaq.push(['_trackPageview']);
            (function() {
            var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
            ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
            var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
            })();
        </script>
    </body>
</html>